package com.yuntsg.ruiijn.database_interior.service;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.TranslogDurability;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuntsg.nnsfcp.common.utils.UserUtil;
import com.yuntsg.ruiijn.database_interior.entity.FileDetailsInterior;
import com.yuntsg.ruiijn.database_interior.entity.FileRecordInterior;
import com.yuntsg.ruiijn.database_interior.entity.InitConfig;
import com.yuntsg.ruiijn.database_interior.mapper.FileDetailInteriorMapper;
import com.yuntsg.ruiijn.databse_search.BaseService;
import com.yuntsg.ruiijn.databse_search.service.FeatureService;
import common.bean.CoordinateVo;
import common.bean.PubSearchRequestVo;
import common.bean.R;
import common.util.MinioUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@Service
@Slf4j
@DS("master")

public class FileDetailInteriorService extends BaseService<FileDetailInteriorMapper, FileDetailsInterior> {


    private static final String SELF_IMAGE_INDEX = "picture_vector_self";
    @Autowired
    private MinioUtil minioUtil;
    @Autowired
    private ElasticsearchClient esClient;
    @Autowired
    private FileRecordInteriorService recordInteriorService;
    @Autowired
    private FeatureService featureService;
    @Autowired
    private FileRecordInteriorService fileRecordInteriorService;

    @Resource
    UserUtil userUtil;

    /**
     * 图片手动切割
     *
     * @return
     * @throws IOException
     */
    public R pictureManually(@RequestBody PubSearchRequestVo requestVo) {
        String originalId = requestVo.getOriginalId();
        FileDetailsInterior fileDetails = this.getById(originalId);

        if (null != requestVo.getCoordinateList() && requestVo.getCoordinateList().size() > 0) {

            for (CoordinateVo coordinateVo : requestVo.getCoordinateList()) {
                Integer xTop = coordinateVo.getTopx();
                Integer yTop = coordinateVo.getTopy();
                Integer xBottom = coordinateVo.getBottomx();
                Integer yBottom = coordinateVo.getBottomy();
                String[] split = fileDetails.getPath().split("/");
                // 保存图片

                String path = fileDetails.getPath().replace(split[split.length - 1], "");

                Mat croppedImage = null;
                try {
                    if (!FileUtil.exist(InitConfig.tempImgPath + path)) {
                        FileUtil.mkdir(InitConfig.tempImgPath + path);
                    }
                    path += RandomUtil.randomString(6) + ".jpg";


                    Mat src = minioUtil.downloadMat(fileDetails.getPath());
                    croppedImage = new Mat(src, new Rect(xTop, yTop, (xBottom - xTop), (yBottom - yTop)));

                } catch (Exception e) {
                    return R.error("图片切割失败,请选择区域重试");
                }

                String docx = minioUtil.upload(MinioUtil.coverInput(croppedImage), path, userUtil.getUidStr());

                FileDetailsInterior fileDetailsS = new FileDetailsInterior();

                fileDetailsS.setFId(fileDetails.getId());
                fileDetailsS.setTpye(6);
                fileDetailsS.setRid(Optional.ofNullable(fileDetails.getRid()).orElse(fileDetailsS.getFId()));
//                fileDetailsS.setCollectionStatus(source);
//                fileDetailsS.setSplitStatus(0);
                fileDetailsS.setCollectionStatus(fileDetails.getCollectionStatus());

                fileDetailsS.setStatus(0);
                fileDetailsS.setPath(docx);
                fileDetailsS.setTopX(xTop);
                fileDetailsS.setTopY(yTop);
                fileDetailsS.setBottomX(xBottom);
                fileDetailsS.setBottomY(yBottom);


                this.saveOrUpdate(fileDetailsS);

            }

        } else {
            return R.error("请选择区域");
        }
        return R.ok();
    }


    public List<FileDetailsInterior> picList(Integer rid, Integer fid, Integer type) {
        return this.list(Wrappers.<FileDetailsInterior>lambdaQuery().eq(FileDetailsInterior::getRid, rid)
                .eq(FileDetailsInterior::getTpye, type)
                .eq(FileDetailsInterior::getFId, fid)
                .eq(FileDetailsInterior::getDeleteFlag, 0));
    }

    /**
     * 同步操作
     *
     * @param code
     * @param ids
     */
    public void putPendingList(Integer code, Integer fid, String[] ids) {
        createIndex(esClient, SELF_IMAGE_INDEX);
        List<FileDetailsInterior> list = this.list(Wrappers.<FileDetailsInterior>lambdaQuery().in(FileDetailsInterior::getId, ids));
        FileDetailsInterior fData = this.getById(fid);
        if (list.size() > 0) {
            FileRecordInterior record = recordInteriorService.getById(list.get(0).getRid());
            List<BulkOperation> eslist = new ArrayList<>();
            for (FileDetailsInterior f : list) {

                try {
                    BooleanResponse exists = esClient.exists(d -> d.index(SELF_IMAGE_INDEX).id(f.getId().toString()));
                    if (exists.value()) {
                        esClient.delete(d -> d.index(SELF_IMAGE_INDEX).id(f.getId().toString()));
                    }
                    Map<String, Object> doc = new HashMap<>();
                    doc.put("id", f.getId());
                    doc.put("pm", record.getPmut());
                    doc.put("rid", record.getId());
                    doc.put("table_no", fData.getTableNo());
                    doc.put("serial_id", fData.getSerialId());
                    doc.put("year", 9999);
                    doc.put("top_x", f.getTopX());
                    doc.put("top_y", f.getTopY());
                    doc.put("bottom_x", f.getBottomX());
                    doc.put("bottom_y", f.getBottomY());
                    doc.put("type", 1);
                    doc.put("img_name", StrUtil.subAfter(f.getPath(), "/", true));
                    doc.put("vector", featureService.imageFeature(f.getPath()));
                    this.saveOrUpdate(f.setSyncStatus(1).setSyncTime(System.currentTimeMillis()).setSyncId(userUtil.getUidStr()));
                    eslist.add(new BulkOperation.Builder().create(builder -> builder.id(f.getId().toString()).index(SELF_IMAGE_INDEX).document(doc)).build());
                } catch (IOException e) {
                    log.error("删除失败:{}", e.getMessage());
                }

            }
            try {
                BulkResponse response = esClient.bulk(builder -> builder.index(SELF_IMAGE_INDEX).operations(eslist));
            } catch (Exception e) {
                log.error("插入失败:{}", e.getMessage());
            }
            fileRecordInteriorService.update(Wrappers.<FileRecordInterior>lambdaUpdate().eq(FileRecordInterior::getId, fData.getRid()).set(FileRecordInterior::getSyncStatus, 1).set(FileRecordInterior::getSyncId, userUtil.getUidStr()).set(FileRecordInterior::getSyncTime, System.currentTimeMillis()));

        }

    }

    public List<FileDetailsInterior> pendinglist(Integer rid) {
        return this.list(Wrappers.<FileDetailsInterior>lambdaQuery().eq(FileDetailsInterior::getSyncStatus, 1).eq(FileDetailsInterior::getRid, rid));
    }

    public void delete(String[] ids) {
        for (String id : ids) {
            try {
                esClient.delete(builder -> builder.index(SELF_IMAGE_INDEX).id(id));
                this.update(Wrappers.<FileDetailsInterior>lambdaUpdate().eq(FileDetailsInterior::getId, id).set(FileDetailsInterior::getSyncStatus, 0).set(FileDetailsInterior::getSyncTime, null).set(FileDetailsInterior::getSyncId, null));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void createIndex(ElasticsearchClient client, String indexName) {
        try {
            if (client.indices().exists(b -> b.index(indexName)).value()) {
                return;
            }
            CreateIndexResponse response = client.indices()
                    .create(builder -> builder
                            .settings(indexSettingsBuilder -> indexSettingsBuilder.numberOfReplicas("0")

                                    .numberOfShards("64").translog(tran -> tran.flushThresholdSize("512mb").durability(TranslogDurability.Async)))
                            .mappings(typeMappingBuilder -> typeMappingBuilder
                                    .properties("id", b -> b.keyword(p -> p))
                                    .properties("pm", b -> b.keyword(p -> p))
                                    .properties("rid", b -> b.keyword(p -> p))
                                    .properties("table_no", b -> b.integer(p -> p))
                                    .properties("serial_id", b -> b.integer(p -> p))
                                    .properties("year", b -> b.integer(p -> p))
                                    .properties("top_x", b -> b.integer(p -> p))
                                    .properties("top_y", b -> b.integer(p -> p))
                                    .properties("bottom_x", b -> b.integer(p -> p))
                                    .properties("bottom_y", b -> b.integer(p -> p))
                                    .properties("img_name", b -> b.text(p -> p))
                                    .properties("type", b -> b.integer(p -> p))
                                    .properties("doi", b -> b.text(p -> p.analyzer("ik_max_word").fields("keyword", r -> r.keyword(m -> m.normalizer("lowercase")))))
                                    .properties("ut", b -> b.text(p -> p.analyzer("ik_max_word").fields("keyword", r -> r.keyword(m -> m.normalizer("lowercase")))))
                                    .properties("vector", propertyBuilder -> propertyBuilder.denseVector(vectorBuilder -> vectorBuilder.dims(512).index(true).similarity("l2_norm")))
                            )
                            .index(indexName));
            log.info("acknowledged={}", response.acknowledged());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
